package cn.lzy.study.ratelimiter.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.scripting.support.ResourceScriptSource;

/**
 * Redis配置
 * 【解释】spring-boot-starter-data-redis 提供了两种对Redis进行操作的类：RedisTemplate(key-value可以为多种类型)、StringRedisTemplate(key-value只可以是String类型)
 * 此处使用RedisTemplate，RedisTemplate默认使用JDK提供的序列化类-JdkSerializationRedisSerializer，
 * 其缺点是存储的键值对均有前缀，可读性差（对键值对进行了序列化，中文字符串序列化后的内容表示为 16 进制表示的数据。 如：存 name zhangsan，序列化后为 \dsxs\dsdf\name \dsxs\dsdf\zhangsan）；内存空间占用大（存储了额外的对象的类型信息）。
 * @author LZY
 * @since 2022-08-16
 */
@Configuration
public class RedisConfig {


    /**
     * 为便于可读性，修改redisTemplate的默认序列化策略
     * 使用Jackson2JsonRedisSerializer序列化策略
     * (注意：由于spring-boot-parent版本问题，可能会导致RedisConnectionFactory注入报错)
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        // 设置redis连接方式
        template.setConnectionFactory(redisConnectionFactory);
        // ======== 设置序列化方案 =======
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        // 给 key 设置序列化方案
        template.setKeySerializer(serializer);
        // 给 hash key 设置序列化方案
        template.setHashKeySerializer(serializer);
        // 给 value 设置序列化方案
        template.setValueSerializer(serializer);
        // 给 hash value 设置序列化方案
        template.setHashValueSerializer(serializer);
        return template;
    }



    /**
     * 加载lua脚本
     * @return
     */
    @Bean
    public DefaultRedisScript<Long> limitScript() {
        DefaultRedisScript<Long> script = new DefaultRedisScript<>();
        // 设置脚本返回的数据类型
        script.setResultType(Long.class);
        // 设置脚本所在的位置
        script.setScriptSource(new ResourceScriptSource(new ClassPathResource("lua/limit.lua")));
        return script;
    }

}
